﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace AssemblyExplorer
{
    public class DefaultDescriptionStrategy : IDescriptionStrategy
    {
        private string FormatAttributeProperties(object attr)
        {
            List<string> list = new List<string>();
            foreach (PropertyInfo pi in attr.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
            {
                list.Add(String.Format("{0} = {1}", pi.Name, pi.GetValue(attr, null)));
            }
            return String.Join(",", list.ToArray());
        }

        public virtual string GetAssemblyDescription(Assembly assembly)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(assembly.FullName);
            sb.AppendLine(assembly.CodeBase);
            sb.AppendLine(assembly.ImageRuntimeVersion);
            foreach (object o in assembly.GetCustomAttributes(false))
            {
                sb.AppendFormat("{0}({1}){2}", o, FormatAttributeProperties(o), Environment.NewLine);
            }
            return sb.ToString();
        }

        public virtual string GetTypeDesription(Type type)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(type.IsPublic ? "public " : "");
            sb.Append(type.IsAbstract ? "abstract " : "");
            sb.Append(type.IsClass ? "class " : (type.IsEnum ? "enum " : (type.IsInterface ? "interface " : "")));
            sb.Append(type.FullName);
            sb.AppendLine(type.Namespace);
            sb.AppendLine(type.GUID.ToString());
            foreach (object o in type.GetCustomAttributes(false))
            {
                sb.AppendFormat("{0}({1}){2}", o, FormatAttributeProperties(o), Environment.NewLine);
            }
            return sb.ToString();
        }

        public virtual string GetMethodDescription(MethodInfo method)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(String.Format("{0} {1}", method.ReturnType.Name, method.Name));
            ParameterInfo[] pis = method.GetParameters();
            sb.Append(FormatParameters(pis));
            return sb.ToString();
        }

        private static string FormatParameters(ParameterInfo[] pis)
        {
            string[] par = new string[pis.Length];
            for (int i = 0; i < pis.Length; i++)
                par[i] = String.Format("{0} {1}", pis[i].ParameterType.Name, pis[i].Name);
            return String.Format("({0})", String.Join(",", par));
        }

        public virtual string GetConstructorDescription(ConstructorInfo ctor)
        {
            return String.Format("{0}{1}", ctor.Name, FormatParameters(ctor.GetParameters()));
        }

        public virtual string GetPropertyDescription(PropertyInfo prop)
        {
            return String.Format("{0} {1}{{{2}{3}}}", prop.PropertyType.Name, prop.Name,
                prop.CanRead ? "get;" : "", prop.CanWrite ? "set;" : "");
        }

        public virtual string GetFieldDescription(FieldInfo field)
        {
            return String.Format("{0} {1}", field.FieldType, field.Name);
        }

        public virtual string GetEventDescription(EventInfo eventInfo)
        {
            return String.Format("{0} {1}", eventInfo.EventHandlerType.Name, eventInfo.Name);
        }
    }
}
